home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / out-of-phase-102-c / OutOfPhase 1.02 Source / OutOfPhase Folder / Level 0 Macintosh 29Sep94 / Memory.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-23  |  12.2 KB  |  514 lines  |  [TEXT/KAHL]

  1. /* Memory.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #ifdef THINK_C
  25.     #pragma options(pack_enums)
  26. #endif
  27. #include <Memory.h>
  28. #include <Errors.h>
  29. #include <Files.h>
  30. #ifdef THINK_C
  31.     #pragma options(!pack_enums)
  32. #endif
  33.  
  34. #include "Memory.h"
  35. #include "MyMalloc.h"
  36.  
  37.  
  38. #define EnableHeapChecking (True)
  39.  
  40. #define MemoryFillPattern (0x81)
  41.  
  42. #if EnableHeapChecking
  43.     #define HEAPCHECK() CheckHeap()
  44. #else
  45.     #define HEAPCHECK() ((void)0)
  46. #endif
  47.  
  48.  
  49. EXECUTE(long NumPtrsAllocated = 0;)
  50. EXECUTE(MyBoolean Initialized = False;)
  51.  
  52. #if MEMDEBUG /* { */
  53.     #define IsANothing (0)
  54.     #define IsAHandle (1)
  55.     #define IsAPointer (2)
  56.     typedef struct StoreRec
  57.         {
  58.             struct StoreRec*    Next;
  59.             void*                            HandPtr; /* whatever it is */
  60.             short                            Type; /* handle or pointer */
  61.             char*                            Tag; /* string for tagging */
  62.         } StoreRec;
  63.     static StoreRec*        TrackList;
  64.     static short                MemDumpFile;
  65.     static MyBoolean        RegisterPointer(char* ThePointer);
  66.     static void                    DeregisterPointer(char* ThePointer);
  67.     static void                    SetUpChecking(void);
  68.     static void                    ShutOffChecking(void);
  69.     static void                    MemPrint(char* Str,...);
  70. #else /* }{ */
  71.     #define RegisterPointer(ThePointer) (True)
  72.     #define DeregisterPointer(ThePointer) ((void)0)
  73.     #define SetUpChecking() ((void)0)
  74.     #define ShutOffChecking() ((void)0)
  75. #endif /* } */
  76.  
  77.  
  78. /* attempt to allocate a pointer */
  79. #if DEBUG
  80.     char*                EepAllocPtr(long Size, char* Tag)
  81. #else
  82.     char*                EepAllocPtr(long Size)
  83. #endif
  84.     {
  85.         char*                        Temp;
  86.  
  87.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  88.         HEAPCHECK();
  89.         ERROR((Size >= 0x00800000 - 16) || (Size < 0),
  90.             PRERR(AllowResume,"AllocPtr:  Requested size is out of range."));
  91.         if ((Size >= 0x00800000 - 16) || (Size < 0))
  92.             {
  93.                 /* this prevents us from crashing in the final version when allocating */
  94.                 /* really big things */
  95.                 return NIL;
  96.             }
  97.         Temp = (char*)BlockNew(Size);
  98. #if DEBUG
  99.         if (Temp != NIL)
  100.             {
  101.                 if (!RegisterPointer(Temp))
  102.                     {
  103.                         BlockRelease(Temp);
  104.                         return NIL;
  105.                     }
  106.             }
  107.         if (Temp != NIL)
  108.             {
  109.                 long                        Scan;
  110.  
  111.                 for (Scan = 0; Scan < Size; Scan += 1)
  112.                     {
  113.                         Temp[Scan] = MemoryFillPattern;
  114.                     }
  115.             }
  116.         if (Temp != NIL)
  117.             {
  118.                 SetTag(Temp,Tag);
  119.             }
  120.         if (Temp != NIL)
  121.             {
  122.                 NumPtrsAllocated += 1;
  123.             }
  124. #endif
  125.         return Temp;
  126.     }
  127.  
  128.  
  129. /* release pointer and attempt to restore cache */
  130. void            ReleasePtr(char* ThePtr)
  131.     {
  132.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  133.         ERROR(ThePtr==NIL,PRERR(ForceAbort,"ReleasePtr:  Tried to dispose a NIL pointer."));
  134. #if DEBUG
  135.         if (ThePtr != NIL)
  136.             {
  137.                 NumPtrsAllocated -= 1;
  138.             }
  139.         {
  140.             long                        Scan;
  141.             long                        Limit;
  142.  
  143.             Limit = PtrSize(ThePtr);
  144.             for (Scan = 0; Scan < Limit; Scan += 1)
  145.                 {
  146.                     ThePtr[Scan] = MemoryFillPattern;
  147.                 }
  148.         }
  149. #endif
  150.         DeregisterPointer(ThePtr);
  151.         BlockRelease(ThePtr);
  152.         HEAPCHECK();
  153.     }
  154.  
  155.  
  156. long            PtrSize(char* p)
  157.     {
  158.         long        Result;
  159.  
  160.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  161.         CheckPtrExistence(p);
  162.         return BlockSize(p);
  163.     }
  164.  
  165.  
  166. char*        ResizePtr(char* ThePointer, long NewSize)
  167.     {
  168.         void*            NewOne;
  169. #if MEMDEBUG
  170.         StoreRec*            Scan;
  171. #endif
  172.  
  173.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  174.         NewOne = BlockResize(ThePointer,NewSize);
  175. #if MEMDEBUG
  176.         Scan = TrackList;
  177.         while (Scan != NIL)
  178.             {
  179.                 if ((Scan->Type == IsAPointer) && (Scan->HandPtr == ThePointer))
  180.                     {
  181.                         Scan->HandPtr = NewOne;
  182.                         goto SpiffyPoint;
  183.                     }
  184.                 Scan = Scan->Next;
  185.             }
  186.         APRINT(("ResizePtr: Undefined pointer used: %r",ThePointer));
  187.         PRERR(ForceAbort,"ResizePtr:  Undefined pointer used.");
  188. #endif
  189.      SpiffyPoint:
  190.         return (char*)NewOne;
  191.     }
  192.  
  193.  
  194. /* initialize the cache */
  195. MyBoolean    Eep_InitMemory(void)
  196.     {
  197.         long            Count;
  198.         MyBoolean    ReturnValue;
  199.  
  200.         APRINT(("+InitMemory"));
  201.         MaxApplZone();
  202.         ERROR(Initialized,PRERR(ForceAbort,"InitMemory called more than once."));
  203.         for (Count = 4; Count >= 0; Count -= 1)
  204.             {
  205.                 MoreMasters();
  206.             }
  207.         SetUpChecking();
  208.         EXECUTE(Initialized = True;)
  209.         ReturnValue = InitializeMyMalloc();
  210.         APRINT(("-InitMemory"));
  211.         return ReturnValue;
  212.     }
  213.  
  214.  
  215. void            Eep_FlushMemory(void)
  216.     {
  217.         APRINT(("+FlushMemory"));
  218.         ERROR(!Initialized,PRERR(ForceAbort,"Memory subsystem hasn't been initialized"));
  219.         ERROR(NumPtrsAllocated!=0,PRERR(AllowResume,
  220.             "FlushMemory:  Some pointers are still allocated just before quitting."));
  221.         ShutOffChecking();
  222.         EXECUTE(Initialized = False;)
  223.         APRINT(("-FlushMemory"));
  224.     }
  225.  
  226.  
  227. #if MEMDEBUG /* { */
  228.  
  229.  
  230. static MyBoolean        RegisterPointer(char* ThePointer)
  231.     {
  232.         StoreRec*                    Temp;
  233.  
  234.         Temp = (StoreRec*)BlockNew(sizeof(StoreRec));
  235.         if (Temp == NIL)
  236.             {
  237.                 return False;
  238.             }
  239.         Temp->Next = TrackList;
  240.         TrackList = (StoreRec*)Temp;
  241.         Temp->Type = IsAPointer;
  242.         Temp->HandPtr = ThePointer;
  243.         Temp->Tag = NIL;
  244.         return True;
  245.     }
  246.  
  247.  
  248. static void                    DeregisterPointer(char* ThePointer)
  249.     {
  250.         StoreRec*                    Scan;
  251.         StoreRec*                    Lag;
  252.         char*                            Temp;
  253.  
  254.         Scan = TrackList;
  255.         Lag = NIL;
  256.         while ((Scan != NIL) && (Scan->HandPtr != ThePointer))
  257.             {
  258.                 Lag = Scan;
  259.                 Scan = Scan->Next;
  260.             }
  261.         if (Scan == NIL)
  262.             {
  263.                 APRINT(("Deletion of nonexistent pointer %r",ThePointer));
  264.                 PRERR(ForceAbort,"Deletion of nonexistent pointer.");
  265.             }
  266.         if (Scan->Type != IsAPointer)
  267.             {
  268.                 APRINT(("Deletion of pointer of unknown type %r",ThePointer));
  269.                 PRERR(ForceAbort,"Deletion of pointer of unknown type.");
  270.             }
  271.         if (Lag == NIL)
  272.             {
  273.                 Temp = (char*)TrackList;
  274.                 TrackList = Scan->Next;
  275.                 BlockRelease(Temp);
  276.             }
  277.          else
  278.             {
  279.                 Temp = (char*)Lag->Next;
  280.                 Lag->Next = Scan->Next;
  281.                 BlockRelease(Temp);
  282.             }
  283.     }
  284.  
  285.  
  286. void            SetTag(void* TheRef, char* TheTag)
  287.     {
  288.         StoreRec*        Scan;
  289.         short                TagScan;
  290.  
  291.         Scan = TrackList;
  292.         while ((Scan != NIL) && (Scan->HandPtr != TheRef))
  293.             {
  294.                 Scan = Scan->Next;
  295.             }
  296.         if (Scan == NIL)
  297.             {
  298.                 PRERR(ForceAbort,"Handle/Ptr couldn't be found by SetTag.");
  299.             }
  300.          else
  301.             {
  302.                 Scan->Tag = TheTag;
  303.             }
  304.     }
  305.  
  306.  
  307. /* this checks to see if a pointer exists.  as a performance enhancement (since */
  308. /* we search this list constantly) referenced elements are moved to the head */
  309. /* of the list */
  310. void        CheckPtrExistence(void* ThePointer)
  311.     {
  312.         StoreRec*            Scan;
  313.         StoreRec*            Lag;
  314.  
  315.         HEAPCHECK();
  316.         if (ThePointer == NIL)
  317.             {
  318.                 PRERR(ForceAbort,"CheckPtrExistence:  Pointer is NIL");
  319.             }
  320.         Lag = NIL;
  321.         Scan = TrackList;
  322.         while (Scan != NIL)
  323.             {
  324.                 if ((Scan->Type == IsAPointer) && (Scan->HandPtr == ThePointer))
  325.                     {
  326.                         /* found -- and correct */
  327.                         if (Lag != NIL)
  328.                             {
  329.                                 /* if element isn't at the beginning of the list, move it */
  330.                                 /* there. */
  331.                                 Lag->Next = Scan->Next; /* removed from old place */
  332.                                 Scan->Next = TrackList; /* added to beginning */
  333.                                 TrackList = Scan;
  334.                             }
  335.                         return;
  336.                     }
  337.                 Lag = Scan;
  338.                 Scan = Scan->Next;
  339.             }
  340.         APRINT(("Undefined pointer used: %r",ThePointer));
  341.         PRERR(ForceAbort,"Undefined pointer used.");
  342.     }
  343.  
  344.  
  345. static void                    SetUpChecking(void)
  346.     {
  347.         TrackList = NIL;
  348.     }
  349.  
  350.  
  351. static void                    ShutOffChecking(void)
  352.     {
  353.         unsigned char            DumpName[] = {"\p!!MemCheck Still Allocated Dump"};
  354.         StoreRec*                    Scan;
  355.         short                            VRefNum;
  356.  
  357.         CheckHeap();
  358.         FSDelete(DumpName,0);
  359.         ERROR(Create(DumpName,0,AUDITCREATOR,'TEXT') != noErr,
  360.             PRERR(ForceAbort,"Memory's ShutOffChecking couldn't create dump file."));
  361.         ERROR(FSOpen(DumpName,0,&MemDumpFile) != noErr,PRERR(ForceAbort,
  362.             "Memory's ShutOffChecking couldn't open dump file for writing."));
  363.         /* MemPrint("These handles and pointers are still allocated:"); */
  364.         Scan = TrackList;
  365.         while (Scan != NIL)
  366.             {
  367.                 switch (Scan->Type)
  368.                     {
  369.                         case IsAHandle:
  370.                             MemPrint("Handle %x '%t'",Scan->HandPtr,Scan->Tag);
  371.                             break;
  372.                         case IsAPointer:
  373.                             MemPrint("Pointer %x '%t'",Scan->HandPtr,Scan->Tag);
  374.                             break;
  375.                     }
  376.                 Scan = Scan->Next;
  377.             }
  378.         GetVRefNum(MemDumpFile,&VRefNum);
  379.         FSClose(MemDumpFile);
  380.         FlushVol("\p",VRefNum);
  381.     }
  382.  
  383.  
  384. /* some va_args crud for MemPrint */
  385. typedef void *va_list;
  386. #define __va(arg)  &arg + 1
  387. #define va_start(p, arg)  p = __va(arg)
  388. #define va_arg(p, type)  *(* (type **) &p)++
  389. #define va_end(p) ((void)0)
  390.  
  391. /* I lifted this from Audit.c */
  392. /* this prints a string in the same way that printf does.  it accepts these options: */
  393. /* %x = hexadecimal long */
  394. /* %t = C String (text) */
  395. #define BUFSIZE (256)
  396. static void                    MemPrint(char* Str,...)
  397.     {
  398.         va_list                        pa;
  399.         char                            Buffer[BUFSIZE];
  400.         long                            BufPtr;
  401.         static char                Hex[] = "0123456789abcdef";
  402.  
  403.         BufPtr = 0;
  404.         va_start(pa,Str);
  405.         while (*Str != 0)
  406.             {
  407.                 if (*Str == '%')
  408.                     {
  409.                         Str += 1;
  410.                         switch (*Str)
  411.                             {
  412.                                 case 'x':
  413.                                     {
  414.                                         char                        Buf[9];
  415.                                         short                        Count;
  416.                                         unsigned long        Num;
  417.  
  418.                                         Num = va_arg(pa,long);
  419.                                         for (Count = 8; Count >= 1; Count -= 1)
  420.                                             {
  421.                                                 Buf[Count] = Hex[Num & 0x0000000f];
  422.                                                 Num = Num >> 4;
  423.                                             }
  424.                                         Buf[0] = '$';
  425.                                         for (Count = 0; Count < 9; Count += 1)
  426.                                             {
  427.                                                 Buffer[BufPtr++] = Buf[Count];
  428.                                                 ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,
  429.                                                     "MemPrint buffer overrun."));
  430.                                             }
  431.                                     }
  432.                                     break;
  433.                                 case 't':
  434.                                     {
  435.                                         char*        Strp;
  436.  
  437.                                         Strp = va_arg(pa,char*);
  438.                                         while (*Strp != 0)
  439.                                             {
  440.                                                 Buffer[BufPtr++] = *(Strp++);
  441.                                             }
  442.                                         ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,"MemPrint buffer overrun."));
  443.                                     }
  444.                                     break;
  445.                             }
  446.                         Str += 1;
  447.                     }
  448.                  else
  449.                     {
  450.                         Buffer[BufPtr++] = *(Str++);
  451.                         ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,"MemPrint buffer overrun."));
  452.                     }
  453.             }
  454.         Buffer[BufPtr++] = 0x0d;
  455.         FSWrite(MemDumpFile,&BufPtr,Buffer);
  456.     }
  457.  
  458.  
  459. #else /* }{  this next part is "#if !MEMDEBUG" */
  460.  
  461.  
  462. #if DEBUG /* { */
  463.  
  464. #define AlignmentMask (0x03) /* should be 0x03??? */
  465.  
  466. /* this is the DEBUG (but not MEMDEBUG) version */
  467. void        CheckPtrExistence(void* ThePointer)
  468.     {
  469.         static MyBoolean        ZoneIsValid = False;
  470.         static Zone*                Zone;
  471.         static char*                ZoneBeginning;
  472.         char*                                ZoneEnd;
  473.  
  474.         /* check for various signs of a bad pointer.  note that the last two */
  475.         /* won't work if you have more than 64 Megabytes. */
  476.         if (!ZoneIsValid)
  477.             {
  478.                 Zone = GetZone();
  479.                 ZoneIsValid = True;
  480.                 ZoneBeginning = (char*)&(Zone->heapData);
  481.             }
  482.         ZoneEnd = (char*)Zone->bkLim;
  483.         if ((((unsigned long)ThePointer & AlignmentMask) != 0) || (ThePointer == NIL)
  484.             || ((char*)ThePointer < ZoneBeginning) || ((char*)ThePointer >= ZoneEnd))
  485.             {
  486.                 PRERR(ForceAbort,"Undefined/Garbage Pointer used.");
  487.                 CheckHeap();
  488.             }
  489.         /* HEAPCHECK(); */
  490.     }
  491.  
  492. #endif /* } */
  493.  
  494.  
  495. #endif /* } */
  496.  
  497.  
  498. #if DEBUG
  499. void            PRNGCHK(void* ThePointer, void* EffectiveAddress, signed long AccessSize)
  500.     {
  501.         signed long            PSize;
  502.         signed long            Difference;
  503.  
  504.         PSize = PtrSize((char*)ThePointer);
  505.         Difference = (char*)EffectiveAddress - (char*)ThePointer;
  506.         if ((Difference < 0) || (Difference + AccessSize > PSize))
  507.             {
  508.                 APRINT(("PRNGCHK pointer access range error: (%xl..%xl):%xl(+%l)",ThePointer,
  509.                     (char*)ThePointer + PSize - 1,EffectiveAddress,AccessSize));
  510.                 PRERR(ForceAbort,"Pointer access out of range.");
  511.             }
  512.     }
  513. #endif
  514.